﻿/**
 * @file aac_decoder_test.cpp
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-03-04
 * @version : 1.0.0.0
 * @brief   : AAC 音频解码（测试 aac_decoder_t）。
 */

#include "audio_aac.h"
#include "fwave_pcm.h"

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif // _MSC_VER

#include <vector>
#include <stdio.h>
#include <errno.h>

/////////////////////////////////////////////////////////////////////////////////

/**********************************************************/
/**
 * @brief 从文件流中读取 ADTS 帧。
 * 
 * @param [out   ] xbuf_frame  : 接收读取到的 ADTS 帧数据。
 * @param [in,out] xut_size    : 入参，xbuf_frame 缓存的容量；
 *                               回参，xbuf_frame 的有效数据长度（ADTS 帧长度）。
 * @param [in    ] faac_reader : 文件流对象。
 * 
 * @return x_int32_t 错误码。
 * @retval  0, 操作成功。
 * @retval -1, 参数有误。
 * @retval -2, 读取 ADTS 头时产生错误。
 * @retval -3, 读取到的 ADTS 头信息格式不正确。
 * @retval -4, 从 ADTS 头信息中解析到的帧长度小于 7 个字节。
 * @retval -5, 帧接收缓存 xbuf_frame 的大小不足以接收当前 ADTS 帧。
 * @retval -6, 读取 ADTS 帧数据时产生错误。
 */
x_int32_t fread_adts(
            x_byte_t * xbuf_frame,
            x_uint32_t & xut_size,
            FILE * faac_reader)
{
    x_int32_t xit_err = -1;
    x_uint32_t xut_fbytes = 0;

    do
    {
        //======================================

        if ((X_NULL == xbuf_frame) || (xut_size < 7) || (X_NULL == faac_reader))
        {
            xit_err = -1;
            break;
        }

        //======================================
        // ADTS header

        if (7 != fread(xbuf_frame, sizeof(x_byte_t), 7, faac_reader))
        {
            xit_err = -2;
            break;
        }

        if ((0xFF != xbuf_frame[0]) || (0xF0 != (xbuf_frame[1] & 0xF0)))
        {
			xit_err = -3;
			break;
		}

        //======================================
        // AAC RAW data

        xut_fbytes = ((((x_uint32_t)xbuf_frame[3]) & 0x03) << 11) |
                     (((x_uint32_t)xbuf_frame[4]) << 3) |
                     (((x_uint32_t)xbuf_frame[5]) >> 5);
        if (xut_fbytes < 7)
        {
            xit_err = -4;
            break;
        }
        if (xut_size < xut_fbytes)
        {
            xut_size = xut_fbytes;

            fseek(faac_reader, -7, SEEK_CUR);
            xit_err = -5;
            break;
        }

        if ((xut_fbytes - 7) !=
            fread(xbuf_frame + 7, sizeof(x_byte_t), xut_fbytes - 7, faac_reader))
        {
            xit_err = -6;
            break;
        }

        xut_size = xut_fbytes;

        //======================================
        xit_err = 0;
    } while (0);

    return xit_err;
}

/////////////////////////////////////////////////////////////////////////////////

int main(int argc, char * argv[])
{
    x_errno_t xerr_no = X_ERR_UNKNOW;
    x_int32_t xit_err = X_ERR_UNKNOW;

    //======================================

    FILE * faac_reader = X_NULL;
    fwave_wpcm_t fwave_wpcm;
    aac_decoder_t aac_decoder;

    x_uint32_t xut_ibytes = 1024 * 1024;
    x_uint32_t xut_obytes = 1024 * 1024;

    std::vector< x_byte_t > xvec_input (xut_ibytes, 0);
    std::vector< x_byte_t > xvec_output(xut_obytes, 0);

    //======================================

    if (argc < 3)
    {
        printf("Usage: \n\t %s < aac-ADTS input file > < wave-pcm-s16 output file >\n", argv[0]);
        return -1;
    }

    //======================================

    faac_reader = fopen(argv[1], "rb");
    if (X_NULL == faac_reader)
    {
        printf("fopen([%s], \"rb\") return X_NULL, errno: %d\n", argv[1], errno);
        return -1;
    }

    //======================================

    xerr_no = aac_decoder.open();
    if (XERR_FAILED(xerr_no))
    {
        printf("aac_decoder.open() return error : %d\n", XERR_HINO(xerr_no));
        if (X_NULL != faac_reader)
        {
            fclose(faac_reader);
            faac_reader = X_NULL;
        }
        return -1;
    }

    //======================================

    x_uint32_t xut_plen = 0;

    while (X_TRUE)
    {
        //======================================
        // read adts frame

        xut_ibytes = (x_uint32_t)xvec_input.size();
        xit_err = fread_adts(xvec_input.data(), xut_ibytes, faac_reader);
        if (0 != xit_err)
        {
            if (!feof(faac_reader))
                printf("fread_adts(...) return error: %d\n", xit_err);
            break;
        }

        //======================================
        // decode aac bitstream

        xut_plen = (x_uint32_t)xvec_output.size();

        xerr_no = aac_decoder.decode(
                        (aac_decoder_t::xpcmbuf_t)xvec_output.data(),
                        xut_plen,
                        xvec_input.data(),
                        xut_ibytes);
        if (XERR_FAILED(xerr_no))
        {
            printf("aac_decoder.decode(, , , [%d], 0) return error: %s\n",
                    xut_ibytes, aac_decoder_t::xerrno_name(xerr_no));
            break;
        }

        //======================================
        // output pcm bitstream

        if (!fwave_wpcm.is_open())
        {
            xerr_no = fwave_wpcm.open(
                            argv[2],
                            aac_decoder.sample_rate(),
                            16,
                            aac_decoder.channels());
            if (XERR_FAILED(xerr_no))
            {
                printf("fwave_wpcm.open([%s], [%d], [%d], [%d]) return error: %s\n",
                        argv[2], aac_decoder.sample_rate(), 16, aac_decoder.channels(),
                        fwave_wpcm_t::xerrno_name(xerr_no));
                break;
            }
        }

        fwave_wpcm.write(xvec_output.data(), xut_plen);

        //======================================
    }

    //======================================

    if (X_NULL != faac_reader)
    {
        fclose(faac_reader);
        faac_reader = X_NULL;
    }

    aac_decoder.close();
    fwave_wpcm.close();

    //======================================

    return 0;
}
